package com.och.mrcp.service;

import com.och.mrcp.config.MrcpConfig;
import com.och.mrcp.config.RtpConfig;
import com.och.mrcp.config.SipConfig;
import com.och.mrcp.core.rtp.session.RtpSession;
import com.och.mrcp.core.rtp.session.RtpSessionManager;
import com.och.mrcp.core.sip.model.SipRequest;
import com.och.mrcp.core.sip.model.SipResponse;
import com.och.mrcp.core.sip.sdp.SdpParser;
import com.och.mrcp.core.sip.sdp.SdpParser.SdpAnswer;
import com.och.mrcp.core.sip.sdp.SdpParser.SdpOffer;
import com.och.mrcp.handler.MrcpMessageSender;
import com.och.mrcp.handler.VoiceRecognitionSessionHandler;
import com.och.mrcp.server.RtpServer;
import com.och.mrcp.util.NetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 媒体会话管理器
 * 通过SIP和MRCP协议协商来管理RTP会话
 * RTP端口不是预先固定的，而是通过SDP协商动态分配
 */
@Slf4j
@Service
public class MediaSessionManager {

    private final RtpSessionManager rtpSessionManager;
    private final RtpServer rtpServer;
    private final SipMrcpSynthesisService sipMrcpSynthesisService;
    private final VoiceRecognitionSessionHandler voiceRecognitionSessionHandler;
    private final SipConfig sipConfig;
    private final MrcpConfig mrcpConfig;
    private final MrcpMessageSender mrcpMessageSender;

    // 媒体会话存储：SIP Call-ID -> MediaSession
    private final Map<String, MediaSession> mediaSessions = new ConcurrentHashMap<>();

    // MRCP Channel-Identifier到SIP Call-ID的映射
    private final Map<String, String> mrcpChannelToCallIdMap = new ConcurrentHashMap<>();

    // RTP会话到Call-ID的映射，用于MRCP消息回调
    private final Map<String, String> rtpSessionToCallIdMap = new ConcurrentHashMap<>();

    // Call-ID到MRCP回调的映射
    private final Map<String, MrcpMessageSender.MrcpMessageCallback> callIdToMrcpCallbackMap = new ConcurrentHashMap<>();

    // 端口分配器：动态分配RTP端口
    private final PortAllocator portAllocator;

    public MediaSessionManager(RtpSessionManager rtpSessionManager, RtpServer rtpServer, SipMrcpSynthesisService sipMrcpSynthesisService, VoiceRecognitionSessionHandler voiceRecognitionSessionHandler, SipConfig sipConfig, MrcpConfig mrcpConfig, MrcpMessageSender mrcpMessageSender, RtpConfig rtpConfig) {
        this.rtpSessionManager = rtpSessionManager;
        this.rtpServer = rtpServer;
        this.sipMrcpSynthesisService = sipMrcpSynthesisService;
        this.voiceRecognitionSessionHandler = voiceRecognitionSessionHandler;
        this.sipConfig = sipConfig;
        this.mrcpConfig = mrcpConfig;
        this.mrcpMessageSender = mrcpMessageSender;
        this.portAllocator = new PortAllocator(rtpConfig.getMinPort(), rtpConfig.getMaxPort()); // 从配置获取RTP端口范围

        // 验证端口配置
        validatePortConfiguration();

        log.info("Media Session Manager initialized with RTP port range: {}-{}", rtpConfig.getMinPort(), rtpConfig.getMaxPort());
    }

    /**
     * 验证端口配置的一致性
     */
    private void validatePortConfiguration() {
        if (sipConfig != null && mrcpConfig != null) {
            log.info("Port configuration - SIP: {} (UDP/TCP), MRCP: {} (TCP)",
                    sipConfig.getLocalPort(), mrcpConfig.getLocalPort());

            // 检查端口冲突
            if (sipConfig.getLocalPort() == mrcpConfig.getLocalPort()) {
                log.warn("SIP and MRCP ports are the same ({}). This may cause conflicts if both services need to bind to the same port.",
                        sipConfig.getLocalPort());
            }

            // 检查端口范围
            if (mrcpConfig.getLocalPort() < 1024 || mrcpConfig.getLocalPort() > 65535) {
                log.warn("MRCP port {} is outside recommended range (1024-65535)", mrcpConfig.getLocalPort());
            }
        }
    }

    /**
     * 注册MRCP Channel-Identifier到SIP Call-ID的映射
     */
    public void registerMrcpChannel(String channelIdentifier, String callId) {
        mrcpChannelToCallIdMap.put(channelIdentifier, callId);
        log.debug("Registered MRCP channel mapping: {} -> {}", channelIdentifier, callId);
    }

    /**
     * 根据MRCP Channel-Identifier查找对应的SIP Call-ID
     */
    public String findCallIdByMrcpChannel(String channelIdentifier) {
        String callId = mrcpChannelToCallIdMap.get(channelIdentifier);
        if (callId != null) {
            log.debug("Found Call-ID for MRCP channel {}: {}", channelIdentifier, callId);
        } else {
            log.debug("No Call-ID found for MRCP channel: {}", channelIdentifier);
        }
        return callId;
    }

    /**
     * 根据Call-ID查找对应的MRCP Channel-Identifier
     */
    public String findMrcpChannelByCallId(String callId) {
        // 遍历映射找到对应的Channel-Identifier
        for (Map.Entry<String, String> entry : mrcpChannelToCallIdMap.entrySet()) {
            if (callId.equals(entry.getValue())) {
                log.debug("Found MRCP channel for Call-ID {}: {}", callId, entry.getKey());
                return entry.getKey();
            }
        }

        // 如果没找到，尝试从MediaSession获取
        MediaSession session = mediaSessions.get(callId);
        if (session != null && session.getChannelId() != null) {
            String resourceType = session.getResourceType() != null ? session.getResourceType() : "speechrecog";
            String channelIdentifier = session.getChannelId() + "@" + resourceType;
            log.debug("Generated MRCP channel from MediaSession for Call-ID {}: {}", callId, channelIdentifier);
            return channelIdentifier;
        }

        log.debug("No MRCP channel found for Call-ID: {}", callId);
        return null;
    }

    /**
     * 获取所有活跃的媒体会话信息
     */
    public void logActiveSessions() {
        log.info("Active media sessions: {}", mediaSessions.size());
        mediaSessions.forEach((callId, session) -> {
            log.info("  Call-ID: {}, RTP-Port: {}, Confirmed: {}, RTP-Active: {}",
                    callId, session.getRtpPort(), session.isConfirmed(), session.isRtpActive());
        });

        log.info("MRCP channel mappings: {}", mrcpChannelToCallIdMap.size());
        mrcpChannelToCallIdMap.forEach((channel, callId) -> {
            log.info("  Channel: {} -> Call-ID: {}", channel, callId);
        });
    }

    /**
     * 处理SIP INVITE请求，协商媒体会话
     * 这是RTP服务启动的入口点
     */
    public SipResponse handleInviteRequest(SipRequest invite, InetSocketAddress sender) {
        String callId = invite.getCallId();
        log.info("Processing INVITE request for Call-ID: {}", callId);

        try {
            // 1. 检查是否已存在相同Call-ID的媒体会话
            MediaSession existingSession = mediaSessions.get(callId);
            if (existingSession != null) {
                log.info("Reusing existing media session for Call-ID: {}, RTP-Port: {}",
                        callId, existingSession.getRtpPort());

                // 更新现有会话的客户端地址（如果发生变化）
                if (!existingSession.getClientAddress().equals(sender)) {
                    log.info("Updating client address for Call-ID: {} from {} to {}",
                            callId, existingSession.getClientAddress(), sender);
                    existingSession.setClientAddress(sender);
                }

                // 解析SDP，获取客户端媒体能力
                SdpOffer clientSdp = parseSdpOffer(invite.getBody());

                // 生成SDP应答，使用现有的RTP端口和通道ID
                SdpAnswer serverSdp = generateSdpAnswerForExistingSession(existingSession, clientSdp);

                // 构建200 OK响应
                SipResponse ok = SipResponse.createResponse(200);
                copyHeaders(invite, ok);
                ok.setBody(serverSdp.toString());
                ok.setContentType("application/sdp");

                // 设置Contact和To-tag
                String contactIp = sipConfig != null ? sipConfig.getLocalIp() : null;
                if (contactIp == null || "127.0.0.1".equals(contactIp) || contactIp.startsWith("0.0.0")) {
                    contactIp = NetUtil.getPrimaryNonLoopbackIp();
                }
                String via = invite.getVia() != null ? invite.getVia() : "";
                boolean isTcp = via.toUpperCase().contains("TCP");
                int contactPort = isTcp ? sipConfig.getTcpPort() : sipConfig.getUdpPort();
                String transport = isTcp ? "tcp" : "udp";
                ok.setContact(String.format("<sip:%s:%d;transport=%s>", contactIp, contactPort, transport));

                // To-tag（简单生成，生产中应更稳健）
                String toTag = "och" + System.currentTimeMillis();
                ok.setHeader("To", ok.getTo() + ";tag=" + toTag);

                // 添加缺失的关键SIP头部
                ok.setHeader("User-Agent", "UniMRCP SofiaSIP 1.8.0");
                ok.setHeader("Accept", "application/sdp");
                ok.setHeader("Allow", "INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE");
                ok.setHeader("Supported", "timer, 100rel");
                ok.setHeader("Session-Expires", "600;refresher=uac");
                ok.setHeader("Min-SE", "120");

                log.info("Reused existing media session for Call-ID: {}, RTP port: {}",
                        callId, existingSession.getRtpPort());

                return ok;
            }

            // 2. 如果不存在，创建新的媒体会话
            SdpOffer clientSdp = parseSdpOffer(invite.getBody());

            // 创建媒体会话
            MediaSession mediaSession = createMediaSession(callId, clientSdp, sender);

            // 生成SDP应答，分配RTP端口
            SdpAnswer serverSdp = generateSdpAnswer(mediaSession, clientSdp);
            // 记录协商后的音频负载类型，供RTP会话使用
            int negotiatedPt = extractNegotiatedAudioPt(serverSdp);
            mediaSession.setNegotiatedPayloadType(negotiatedPt);

            // 4. 构建200 OK响应
            SipResponse ok = SipResponse.createResponse(200);
            copyHeaders(invite, ok);
            ok.setBody(serverSdp.toString());
            ok.setContentType("application/sdp");

            // 设置Contact和To-tag，确保对端识别对话
            String contactIp = sipConfig != null ? sipConfig.getLocalIp() : null;
            if (contactIp == null || "127.0.0.1".equals(contactIp) || contactIp.startsWith("0.0.0")) {
                contactIp = NetUtil.getPrimaryNonLoopbackIp();
            }
            String via = invite.getVia() != null ? invite.getVia() : "";
            boolean isTcp = via.toUpperCase().contains("TCP");
            int contactPort = isTcp ? sipConfig.getTcpPort() : sipConfig.getUdpPort();
            String transport = isTcp ? "tcp" : "udp";
            ok.setContact(String.format("<sip:%s:%d;transport=%s>", contactIp, contactPort, transport));

            // To-tag（简单生成，生产中应更稳健）
            String toTag = "och" + System.currentTimeMillis();
            ok.setHeader("To", ok.getTo() + ";tag=" + toTag);

            // 添加缺失的关键SIP头部
            ok.setHeader("User-Agent", "UniMRCP SofiaSIP 1.8.0");
            ok.setHeader("Accept", "application/sdp");
            ok.setHeader("Allow", "INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE");
            ok.setHeader("Supported", "timer, 100rel");
            ok.setHeader("Session-Expires", "600;refresher=uac");
            ok.setHeader("Min-SE", "120");

            log.info("Media session established for Call-ID: {}, RTP port: {}",
                    callId, mediaSession.getRtpPort());

            return ok;

        } catch (Exception e) {
            log.error("Failed to handle INVITE request for Call-ID {}: {}", callId, e.getMessage(), e);

            // 发送500错误响应
            SipResponse error = SipResponse.createResponse(500);
            copyHeaders(invite, error);
            error.setHeader("To", error.getTo() + ";tag=och" + System.currentTimeMillis());
            return error;
        }
    }

    /**
     * 处理SIP ACK请求，确认媒体会话
     */
    public void handleAckRequest(SipRequest ack, InetSocketAddress sender) {
        String callId = ack.getCallId();
        MediaSession session = mediaSessions.get(callId);

        if (session != null) {
            // 标记会话为已确认
            session.setConfirmed(true);

            // 启动RTP会话（因为ACK确认了媒体会话）
            if (!session.isRtpActive()) {
                log.info("Starting RTP session after ACK confirmation for Call-ID: {}", callId);
                startRtpSession(session);
            }

            log.info("Media session confirmed for Call-ID: {}", callId);
        } else {
            log.warn("No media session found for Call-ID: {}", callId);
        }
    }

    /**
     * 处理SIP BYE请求，终止媒体会话
     */
    public void handleByeRequest(SipRequest bye, InetSocketAddress sender) {
        String callId = bye.getCallId();
        MediaSession session = mediaSessions.remove(callId);

        if (session != null) {
            terminateMediaSession(session);
            log.info("Media session terminated for Call-ID: {}", callId);
        } else {
            log.warn("No media session found for Call-ID: {}", callId);
        }
    }

    /**
     * 处理MRCP请求，在已建立的媒体会话中执行语音操作
     * 这是RTP服务启动的正确时机
     */
    public void handleMrcpRequest(String callId, String mrcpMessage) {
        MediaSession session = mediaSessions.get(callId);
        if (session == null) {
            log.warn("No media session found for Call-ID: {}", callId);
            return;
        }

        // 检查媒体会话是否已确认
        if (!session.isConfirmed()) {
            log.warn("Media session not confirmed for Call-ID: {}", callId);
            return;
        }

        // 解析MRCP消息类型
        MrcpMessageType messageType = parseMrcpMessageType(mrcpMessage);

        // 根据MRCP消息类型决定是否启动RTP
        switch (messageType) {
            case SPEAK:
            case RECOGNIZE:
            case START_INPUT_TIMERS:
                // 这些操作需要RTP，启动RTP会话
                if (!session.isRtpActive()) {
                    startRtpSession(session);
                }
                break;

            case STOP:
            case GET_PARAMS:
            case SET_PARAMS:
                // 这些操作不需要RTP，保持现有状态
                break;

            default:
                log.warn("Unknown MRCP message type: {}", messageType);
                break;
        }

        // 处理MRCP请求
        processMrcpRequest(session, mrcpMessage);
    }

    /**
     * 处理MRCP事件，如SPEAK-COMPLETE等
     * 当MRCP操作完成时，可以选择性地停止RTP（如果不再需要）
     */
    public void handleMrcpEvent(String callId, String mrcpEvent) {
        MediaSession session = mediaSessions.get(callId);
        if (session == null) {
            log.warn("No media session found for Call-ID: {}", callId);
            return;
        }

        // 解析MRCP事件类型
        MrcpEventType eventType = parseMrcpEventType(mrcpEvent);

        // 根据事件类型决定是否停止RTP
        switch (eventType) {
            case SPEAK_COMPLETE:
            case RECOGNITION_COMPLETE:
                // 语音操作完成，清理语音合成会话
                log.info("MRCP operation completed, cleaning synthesis session for Call-ID: {}", callId);
                sipMrcpSynthesisService.cleanupSession(callId);

                // 检查是否需要保持RTP活跃
                if (!hasPendingMrcpOperations(session)) {
                    log.info("No pending operations, stopping RTP for Call-ID: {}", callId);
                    stopRtpSession(session);
                }
                break;

            case START_OF_INPUT:
            case RECOGNITION_STARTED:
                // 输入开始，确保RTP保持活跃
                if (!session.isRtpActive()) {
                    log.info("Input started, ensuring RTP is active for Call-ID: {}", callId);
                    startRtpSession(session);
                }
                break;

            default:
                log.debug("Unhandled MRCP event: {} for Call-ID: {}", eventType, callId);
                break;
        }
    }

    /**
     * 创建媒体会话
     */
    private MediaSession createMediaSession(String callId, SdpOffer clientSdp, InetSocketAddress sender) {
        // 分配RTP端口
        int rtpPort = portAllocator.allocatePort();

        // 从 SDP 中解析客户端的 RTP 端口
        InetSocketAddress clientRtpAddress = extractClientRtpAddress(clientSdp, sender);

        MediaSession session = new MediaSession();
        session.setCallId(callId);
        session.setClientAddress(clientRtpAddress);  // 使用客户端的 RTP 地址
        session.setRtpPort(rtpPort);
        session.setClientSdp(clientSdp);
        session.setCreatedTime(System.currentTimeMillis());

        mediaSessions.put(callId, session);

        log.info("Created media session: Call-ID={}, RTP-Port={}, Client-RTP={}",
                callId, rtpPort, clientRtpAddress);
        return session;
    }

    /**
     * 从 SDP 中提取客户端 RTP 地址
     */
    private InetSocketAddress extractClientRtpAddress(SdpOffer clientSdp, InetSocketAddress sipSender) {
        try {
            // 查找音频媒体描述
            for (SdpParser.MediaDescription media : clientSdp.getMediaDescriptions()) {
                if ("audio".equals(media.getMediaType())) {
                    int clientRtpPort = media.getPort();
                    // 使用 SIP 发送者的 IP 地址，但使用 SDP 中的 RTP 端口
                    return new InetSocketAddress(sipSender.getAddress(), clientRtpPort);
                }
            }
        } catch (Exception e) {
            log.warn("Failed to extract client RTP address from SDP, using SIP sender address: {}", e.getMessage());
        }

        // 如果无法解析，回退到 SIP 发送者地址
        return sipSender;
    }

    /**
     * 启动RTP会话
     */
    private void startRtpSession(MediaSession session) {
        try {
            log.info("Starting RTP session for Call-ID: {}, Port: {}",
                    session.getCallId(), session.getRtpPort());

            // 1. 在指定端口启动RTP监听
            if (!rtpServer.isPortListening(session.getRtpPort())) {
                log.info("Starting RTP listener on port {} for Call-ID: {}",
                        session.getRtpPort(), session.getCallId());
                if (!rtpServer.startPort(session.getRtpPort())) {
                    throw new RuntimeException("Failed to start RTP listener on port " + session.getRtpPort());
                }
                log.info("RTP listener started successfully on port {} for Call-ID: {}",
                        session.getRtpPort(), session.getCallId());
            } else {
                log.info("RTP listener already active on port {} for Call-ID: {}",
                        session.getRtpPort(), session.getCallId());
            }

            // 2. 创建RTP会话
            InetSocketAddress localAddress = new InetSocketAddress("0.0.0.0", session.getRtpPort());
            InetSocketAddress remoteAddress = session.getClientAddress();

            log.info("Creating RTP session: local={}, remote={} for Call-ID: {}",
                    localAddress, remoteAddress, session.getCallId());

            RtpSession rtpSession = rtpSessionManager.createSession(localAddress, remoteAddress);
            // 设置协商后的RTP参数
            try {
                int pt = session.getNegotiatedPayloadType();
                if (pt > 0) {
                    rtpSession.setPayloadType(pt);
                    if (pt == 0 || pt == 8) {
                        rtpSession.setSampleRate(8000);
                        rtpSession.setChannels(1);
                    } else if (pt == 9) { // G722 常见8k封装
                        rtpSession.setSampleRate(8000);
                        rtpSession.setChannels(1);
                    }
                    log.info("Set RTP payload type: {}, sample rate: {}, channels: {} for Call-ID: {}",
                            pt, rtpSession.getSampleRate(), rtpSession.getChannels(), session.getCallId());
                }
            } catch (Exception ignored) {
                log.warn("Failed to set RTP parameters for Call-ID: {}", session.getCallId());
            }
            session.setRtpSession(rtpSession);

            // 设置MRCP Channel-Identifier到RTP会话
            String channelIdentifier = findMrcpChannelByCallId(session.getCallId());
            if (channelIdentifier != null) {
                rtpSession.setChannelIdentifier(channelIdentifier);
                log.info("Set Channel-Identifier {} for RTP session: {}", channelIdentifier, rtpSession.getSessionId());
            } else {
                log.warn("No Channel-Identifier found for Call-ID: {}", session.getCallId());
            }

            // 3. 注意：语音识别处理器现在通过新的架构管理，不需要手动设置
            log.info("Voice recognition handler is managed by the new session architecture for RTP session: {}", rtpSession.getSessionId());

            // 4. 注册MRCP消息回调，将RTP会话连接到MRCP通道
            registerMrcpCallbackForRtpSession(rtpSession.getSessionId(), session.getCallId());

            // 5. 启动RTP会话
            rtpSessionManager.startSession(rtpSession.getSessionId());
            session.setRtpActive(true);

            log.info("RTP session started successfully for Call-ID: {}, Port: {}, Session ID: {}",
                    session.getCallId(), session.getRtpPort(), rtpSession.getSessionId());

        } catch (Exception e) {
            log.error("Failed to start RTP session for Call-ID: {}: {}",
                    session.getCallId(), e.getMessage(), e);
            session.setRtpActive(false);
        }
    }

    /**
     * 终止媒体会话
     */
    private void terminateMediaSession(MediaSession session) {
        try {
            // 1. 终止RTP会话并通知VoiceRecognitionSessionHandler会话终止
            if (session.getRtpSession() != null) {
                String rtpSessionId = session.getRtpSession().getSessionId();
                String sessionId = getCallIdByRtpSessionId(rtpSessionId);
                // 使用带回调的terminateSession方法，确保通知语音识别会话管理器
                rtpSessionManager.terminateSession(rtpSessionId, () -> {
                    try {
                        log.info("Notifying voice recognition session handler about session termination: {}", sessionId);
                        voiceRecognitionSessionHandler.handleSessionTerminationInternal(sessionId);
                    } catch (Exception e) {
                        log.warn("Error notifying voice recognition session handler: {}", e.getMessage(), e);
                    }
                });
                
                session.setRtpActive(false);
            }

            // 2. 停止RTP端口监听
            if (rtpServer.isPortListening(session.getRtpPort())) {
                rtpServer.stopPort(session.getRtpPort());
            }

            // 3. 释放端口
            portAllocator.releasePort(session.getRtpPort());

            log.info("Media session terminated: Call-ID={}, RTP-Port={}",
                    session.getCallId(), session.getRtpPort());

        } catch (Exception e) {
            log.error("Error terminating media session: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理MRCP请求
     */
    private void processMrcpRequest(MediaSession session, String mrcpMessage) {
        try {
            log.info("Processing MRCP request for Call-ID: {}, message: {}",
                    session.getCallId(), mrcpMessage);

            // 解析MRCP消息类型
            MrcpMessageType messageType = parseMrcpMessageType(mrcpMessage);

            // 根据消息类型进行相应处理
            switch (messageType) {
                case SPEAK:
                    log.info("Processing SPEAK request for Call-ID: {}", session.getCallId());
                    // SPEAK请求已经在VoiceSessionManager中处理
                    break;

                case RECOGNIZE:
                    log.info("Processing RECOGNIZE request for Call-ID: {}", session.getCallId());
                    // RECOGNIZE请求已经在VoiceSessionManager中处理
                    break;

                case START_INPUT_TIMERS:
                    log.info("Processing START-INPUT-TIMERS request for Call-ID: {}", session.getCallId());
                    // 启动输入计时器，确保RTP会话活跃
                    if (!session.isRtpActive()) {
                        startRtpSession(session);
                    }
                    break;

                case STOP:
                    log.info("Processing STOP request for Call-ID: {}", session.getCallId());
                    // 停止当前操作，但保持RTP会话活跃
                    break;

                case GET_PARAMS:
                case SET_PARAMS:
                    log.info("Processing {} request for Call-ID: {}", messageType, session.getCallId());
                    // 参数操作不需要RTP，记录日志即可
                    break;

                default:
                    log.warn("Unknown MRCP message type: {} for Call-ID: {}",
                            messageType, session.getCallId());
                    break;
            }

        } catch (Exception e) {
            log.error("Error processing MRCP request for Call-ID: {}", session.getCallId(), e);
        }
    }

    /**
     * 解析SDP Offer
     */
    private SdpOffer parseSdpOffer(String sdpBody) {
        try {
            return SdpParser.parseOffer(sdpBody);
        } catch (Exception e) {
            log.error("Failed to parse SDP offer: {}", e.getMessage(), e);
            throw new RuntimeException("SDP parsing failed", e);
        }
    }
    
    /**
     * 从SDP中检测资源类型
     */
    private String detectResourceTypeFromSdp(SdpOffer clientSdp) {
        try {
            // 查找application媒体描述中的resource属性
            for (SdpParser.MediaDescription media : clientSdp.getMediaDescriptions()) {
                if ("application".equals(media.getMediaType())) {
                    for (String attribute : media.getAttributes()) {
                        if (attribute.startsWith("resource:")) {
                            String resourceType = attribute.substring("resource:".length()).trim();
                            log.debug("Detected resource type from SDP: {}", resourceType);
                            return resourceType;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("Failed to detect resource type from SDP: {}", e.getMessage());
        }
        
        // 默认返回speechrecog（向后兼容）
        log.debug("No resource type found in SDP, defaulting to speechrecog");
        return "speechrecog";
    }

    /**
     * 生成SDP应答
     */
    private SdpAnswer generateSdpAnswer(MediaSession mediaSession, SdpOffer clientSdp) {
        try {
            // 生成唯一的MRCP通道标识
            String channelId = generateChannelId();
            
            // 检测客户端请求的资源类型
            String resourceType = detectResourceTypeFromSdp(clientSdp);

            // 创建SDP应答
            SdpAnswer answer = new SdpAnswer();
            answer.setVersion("0");
            answer.setOrigin("UniMRCPServer " + System.currentTimeMillis() + " " + System.nanoTime() + " IN IP4 " + getLocalIp());
            answer.setSessionName("-");
            answer.setConnectionInfo("IN IP4 " + getLocalIp());
            answer.setTimeDescription("0 0");

            // 添加MRCP控制通道
            SdpParser.MediaDescription mrcpMedia = new SdpParser.MediaDescription();
            mrcpMedia.setMediaType("application");
            int mrcpPort = mrcpConfig.getLocalPort();
            mrcpMedia.setPort(mrcpPort); // 使用配置的MRCP端口
            mrcpMedia.setTransport("TCP/MRCPv2");
            mrcpMedia.setPayloadType(1);

            log.debug("Setting MRCP port in SDP: {} (config: {})", mrcpPort, mrcpConfig.getLocalPort());

            // 添加MRCP关键属性
            mrcpMedia.addAttribute("setup:passive");
            mrcpMedia.addAttribute("connection:new");
            mrcpMedia.addAttribute("channel:" + channelId + "@" + resourceType); // 动态设置资源类型
            mrcpMedia.addAttribute("cmid:1");

            answer.addMediaDescription(mrcpMedia);

            // 添加音频通道
            SdpParser.MediaDescription audioMedia = new SdpParser.MediaDescription();
            audioMedia.setMediaType("audio");
            audioMedia.setPort(mediaSession.getRtpPort()); // 使用实际分配的 RTP 端口
            audioMedia.setTransport("RTP/AVP");
            audioMedia.setPayloadType(0);
            audioMedia.addFormat(0);
            audioMedia.addFormat(101);

            // 添加音频属性
            audioMedia.addAttribute("rtpmap:0 PCMU/8000");
            audioMedia.addAttribute("rtpmap:101 telephone-event/8000");
            audioMedia.addAttribute("fmtp:101 0-15");
            // 根据资源类型设置媒体方向：TTS为sendonly，ASR为recvonly
            if ("speechsynth".equalsIgnoreCase(resourceType)) {
                audioMedia.addAttribute("sendonly");
            } else {
                audioMedia.addAttribute("recvonly");
            }
            audioMedia.addAttribute("ptime:20");
            audioMedia.addAttribute("mid:1");

            answer.addMediaDescription(audioMedia);

            // 存储通道ID和资源类型到媒体会话
            mediaSession.setChannelId(channelId);
            mediaSession.setResourceType(resourceType);

            // 注册MRCP Channel-Identifier到SIP Call-ID的映射
            String fullChannelId = channelId + "@" + resourceType;
            registerMrcpChannel(fullChannelId, mediaSession.getCallId());

            log.info("Generated SDP answer with MRCP channel: {}@{}, RTP port: {} for Call-ID: {}",
                    channelId, resourceType, mediaSession.getRtpPort(), mediaSession.getCallId());

            return answer;

        } catch (Exception e) {
            log.error("Failed to generate SDP answer: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to generate SDP answer", e);
        }
    }

    /**
     * 生成SDP应答（用于重用现有会话）
     */
    private SdpAnswer generateSdpAnswerForExistingSession(MediaSession existingSession, SdpOffer clientSdp) {
        try {
            // 使用现有的通道ID和RTP端口
            String channelId = existingSession.getChannelId();
            int rtpPort = existingSession.getRtpPort();

            // 创建SDP应答
            SdpAnswer answer = new SdpAnswer();
            answer.setVersion("0");
            answer.setOrigin("UniMRCPServer " + System.currentTimeMillis() + " " + System.nanoTime() + " IN IP4 " + getLocalIp());
            answer.setSessionName("-");
            answer.setConnectionInfo("IN IP4 " + getLocalIp());
            answer.setTimeDescription("0 0");

            // 添加MRCP控制通道
            SdpParser.MediaDescription mrcpMedia = new SdpParser.MediaDescription();
            mrcpMedia.setMediaType("application");
            int mrcpPort = mrcpConfig.getLocalPort();
            mrcpMedia.setPort(mrcpPort); // 使用配置的MRCP端口
            mrcpMedia.setTransport("TCP/MRCPv2");
            mrcpMedia.setPayloadType(1);

            log.debug("Setting MRCP port in SDP for existing session: {} (config: {})", mrcpPort, mrcpConfig.getLocalPort());

            // 添加MRCP关键属性
            mrcpMedia.addAttribute("setup:passive");
            mrcpMedia.addAttribute("connection:new");
            mrcpMedia.addAttribute("channel:" + channelId + "@" + existingSession.getResourceType()); // 使用会话的资源类型
            mrcpMedia.addAttribute("cmid:1");

            answer.addMediaDescription(mrcpMedia);

            // 添加音频通道
            SdpParser.MediaDescription audioMedia = new SdpParser.MediaDescription();
            audioMedia.setMediaType("audio");
            audioMedia.setPort(rtpPort); // 使用现有的RTP端口
            audioMedia.setTransport("RTP/AVP");
            audioMedia.setPayloadType(0);
            audioMedia.addFormat(0);
            audioMedia.addFormat(101);

            // 添加音频属性
            audioMedia.addAttribute("rtpmap:0 PCMU/8000");
            audioMedia.addAttribute("rtpmap:101 telephone-event/8000");
            audioMedia.addAttribute("fmtp:101 0-15");
            // 根据资源类型设置媒体方向：TTS为sendonly，ASR为recvonly
            if ("speechsynth".equalsIgnoreCase(existingSession.getResourceType())) {
                audioMedia.addAttribute("sendonly");
            } else {
                audioMedia.addAttribute("recvonly");
            }
            audioMedia.addAttribute("ptime:20");
            audioMedia.addAttribute("mid:1");

            answer.addMediaDescription(audioMedia);

            // 注册MRCP Channel-Identifier到SIP Call-ID的映射
            String fullChannelId = channelId + "@" + existingSession.getResourceType();
            registerMrcpChannel(fullChannelId, existingSession.getCallId());

            log.info("Generated SDP answer for existing media session: Call-ID={}, RTP-Port={}",
                    existingSession.getCallId(), rtpPort);

            return answer;

        } catch (Exception e) {
            log.error("Failed to generate SDP answer for existing media session: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to generate SDP answer for existing media session", e);
        }
    }

    /**
     * 生成唯一的MRCP通道标识
     */
    private String generateChannelId() {
        return Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime());
    }

    /**
     * 获取本地IP地址
     */
    private String getLocalIp() {
        String serverIp = sipConfig != null ? sipConfig.getLocalIp() : null;
        if (serverIp == null || "127.0.0.1".equals(serverIp) || serverIp.startsWith("0.0.0")) {
            serverIp = NetUtil.getPrimaryNonLoopbackIp();
        }
        return serverIp;
    }

    /**
     * 从SDP应答中提取协商的音频负载类型
     */
    private int extractNegotiatedAudioPt(SdpAnswer answer) {
        try {
            for (SdpParser.MediaDescription md : answer.getMediaDescriptions()) {
                if ("audio".equalsIgnoreCase(md.getMediaType())) {
                    return md.getPayloadType();
                }
            }
        } catch (Exception ignored) {
        }
        return 8; // 默认PCMA
    }

    /**
     * 复制SIP头部
     */
    private void copyHeaders(SipRequest source, SipResponse target) {
        try {
            // 复制必要的SIP头部
            if (source.getCallId() != null) {
                target.setCallId(source.getCallId());
            }

            if (source.getCseq() != null) {
                target.setCseq(source.getCseq());
            }

            if (source.getFrom() != null) {
                target.setFrom(source.getFrom());
            }

            if (source.getTo() != null) {
                target.setTo(source.getTo());
            }

            if (source.getVia() != null) {
                target.setVia(source.getVia());
            }

            // 复制其他可选头部
            if (source.getContact() != null) {
                target.setContact(source.getContact());
            }

            if (source.getUserAgent() != null) {
                target.setUserAgent(source.getUserAgent());
            }

            log.debug("SIP headers copied from request to response for Call-ID: {}",
                    source.getCallId());

        } catch (Exception e) {
            log.error("Error copying SIP headers", e);
        }
    }

    /**
     * 获取活跃的媒体会话数量
     */
    public int getActiveSessionCount() {
        return mediaSessions.size();
    }

    /**
     * 获取所有活跃的Call-ID
     */
    public Set<String> getActiveCallIds() {
        return new HashSet<>(mediaSessions.keySet());
    }

    /**
     * 获取媒体会话信息
     */
    public MediaSession getMediaSession(String callId) {
        return mediaSessions.get(callId);
    }

    /**
     * 媒体会话
     */
    public static class MediaSession {
        private String callId;
        private InetSocketAddress clientAddress;
        private int rtpPort;
        private SdpOffer clientSdp;
        private RtpSession rtpSession;
        private boolean confirmed = false;
        private boolean rtpActive = false;
        private long createdTime;
        private String channelId; // 添加MRCP通道标识字段
        private String resourceType; // 添加资源类型字段（speechsynth/speechrecog）

        // Getters and setters
        public String getCallId() {
            return callId;
        }

        public void setCallId(String callId) {
            this.callId = callId;
        }

        public InetSocketAddress getClientAddress() {
            return clientAddress;
        }

        public void setClientAddress(InetSocketAddress clientAddress) {
            this.clientAddress = clientAddress;
        }

        public int getRtpPort() {
            return rtpPort;
        }

        public void setRtpPort(int rtpPort) {
            this.rtpPort = rtpPort;
        }

        public SdpOffer getClientSdp() {
            return clientSdp;
        }

        public void setClientSdp(SdpOffer clientSdp) {
            this.clientSdp = clientSdp;
        }

        public RtpSession getRtpSession() {
            return rtpSession;
        }

        public void setRtpSession(RtpSession rtpSession) {
            this.rtpSession = rtpSession;
        }

        public boolean isConfirmed() {
            return confirmed;
        }

        public void setConfirmed(boolean confirmed) {
            this.confirmed = confirmed;
        }

        public boolean isRtpActive() {
            return rtpActive;
        }

        public void setRtpActive(boolean rtpActive) {
            this.rtpActive = rtpActive;
        }

        public long getCreatedTime() {
            return createdTime;
        }

        public void setCreatedTime(long createdTime) {
            this.createdTime = createdTime;
        }

        public String getChannelId() {
            return channelId;
        }

        public void setChannelId(String channelId) {
            this.channelId = channelId;
        }

        public String getResourceType() {
            return resourceType;
        }

        public void setResourceType(String resourceType) {
            this.resourceType = resourceType;
        }

        public int getNegotiatedPayloadType() {
            return 0;
        } // 默认PCMU

        public void setNegotiatedPayloadType(int payloadType) { /* 可以扩展实现 */ }
    }


    /**
     * 端口分配器
     * 动态分配RTP端口，避免冲突
     */
    private static class PortAllocator {
        private final int minPort;
        private final int maxPort;
        private final AtomicInteger nextPort;

        public PortAllocator(int minPort, int maxPort) {
            this.minPort = minPort;
            this.maxPort = maxPort;
            this.nextPort = new AtomicInteger(minPort);
        }

        public synchronized int allocatePort() {
            int port = nextPort.getAndIncrement();
            if (port > maxPort) {
                nextPort.set(minPort);
                port = nextPort.getAndIncrement();
            }
            return port;
        }

        public synchronized void releasePort(int port) {
            // 端口会自动重用，这里可以添加端口状态管理
            log.debug("Released RTP port: {}", port);
        }
    }

    /**
     * MRCP消息类型枚举
     */
    private enum MrcpMessageType {
        SPEAK,              // 语音合成
        RECOGNIZE,          // 语音识别
        START_INPUT_TIMERS, // 开始输入计时器
        STOP,               // 停止操作
        GET_PARAMS,         // 获取参数
        SET_PARAMS,         // 设置参数
        UNKNOWN             // 未知类型
    }

    /**
     * 解析MRCP消息类型
     */
    private MrcpMessageType parseMrcpMessageType(String mrcpMessage) {
        if (mrcpMessage == null || mrcpMessage.trim().isEmpty()) {
            return MrcpMessageType.UNKNOWN;
        }

        String message = mrcpMessage.trim().toUpperCase();

        if (message.contains("SPEAK")) {
            return MrcpMessageType.SPEAK;
        } else if (message.contains("RECOGNIZE")) {
            return MrcpMessageType.RECOGNIZE;
        } else if (message.contains("START-INPUT-TIMERS")) {
            return MrcpMessageType.START_INPUT_TIMERS;
        } else if (message.contains("STOP")) {
            return MrcpMessageType.STOP;
        } else if (message.contains("GET-PARAMS")) {
            return MrcpMessageType.GET_PARAMS;
        } else if (message.contains("SET-PARAMS")) {
            return MrcpMessageType.SET_PARAMS;
        }

        return MrcpMessageType.UNKNOWN;
    }

    /**
     * MRCP事件类型枚举
     */
    private enum MrcpEventType {
        SPEAK_COMPLETE,        // 语音合成完成
        RECOGNITION_COMPLETE,  // 语音识别完成
        START_OF_INPUT,        // 开始输入
        RECOGNITION_STARTED,   // 识别开始
        UNKNOWN                // 未知事件
    }

    /**
     * 解析MRCP事件类型
     */
    private MrcpEventType parseMrcpEventType(String mrcpEvent) {
        if (mrcpEvent == null || mrcpEvent.trim().isEmpty()) {
            return MrcpEventType.UNKNOWN;
        }

        String event = mrcpEvent.trim().toUpperCase();

        if (event.contains("SPEAK-COMPLETE")) {
            return MrcpEventType.SPEAK_COMPLETE;
        } else if (event.contains("RECOGNITION-COMPLETE")) {
            return MrcpEventType.RECOGNITION_COMPLETE;
        } else if (event.contains("START-OF-INPUT")) {
            return MrcpEventType.START_OF_INPUT;
        } else if (event.contains("RECOGNITION-STARTED")) {
            return MrcpEventType.RECOGNITION_STARTED;
        }

        return MrcpEventType.UNKNOWN;
    }

    /**
     * 检查会话是否有待处理的MRCP操作
     */
    private boolean hasPendingMrcpOperations(MediaSession session) {
        try {
            // 检查是否有活跃的语音合成会话
            try {
                SipMrcpSynthesisService.SynthesisSession synthSession = sipMrcpSynthesisService.getSynthesisSession(session.getCallId());
                if (synthSession != null && synthSession.getStatus() != SipMrcpSynthesisService.SynthesisStatus.STOPPED) {
                    log.debug("Synthesis session is active for Call-ID: {}", session.getCallId());
                    return true;
                }
            } catch (Exception ignored) {}

            // 检查RTP会话状态
            if (session.isRtpActive() && session.getRtpSession() != null) {
                // 检查RTP会话是否有待处理的数据
                // 这里可以根据RTP会话的状态来判断
                log.debug("RTP session is active for Call-ID: {}", session.getCallId());
                return true;
            }

            // 检查会话创建时间，如果太新可能还有操作在进行
            long sessionAge = System.currentTimeMillis() - session.getCreatedTime();
            if (sessionAge < 5000) { // 5秒内的会话可能还有操作
                log.debug("Session is new ({}ms old) for Call-ID: {}", sessionAge, session.getCallId());
                return true;
            }

            log.debug("No pending operations for Call-ID: {}", session.getCallId());
            return false;

        } catch (Exception e) {
            log.error("Error checking pending operations for Call-ID: {}", session.getCallId(), e);
            // 出错时保守处理，认为有待处理操作
            return true;
        }
    }

    /**
     * 停止RTP会话（但不终止整个媒体会话）
     */
    private void stopRtpSession(MediaSession session) {
        try {
            if (session.getRtpSession() != null) {
                rtpSessionManager.terminateSession(session.getRtpSession().getSessionId());
                session.setRtpActive(false);
                log.info("RTP session stopped for Call-ID: {}, Port: {}",
                        session.getCallId(), session.getRtpPort());
            }
        } catch (Exception e) {
            log.error("Error stopping RTP session: {}", e.getMessage(), e);
        }
    }

    /**
     * 为RTP会话注册MRCP消息回调
     * 将RTP会话ID映射到相应的MRCP通道，以便VoiceRecognitionSessionHandler可以发送MRCP消息
     */
    private void registerMrcpCallbackForRtpSession(String rtpSessionId, String callId) {
        try {
            // 1. 记录RTP会话到Call-ID的映射
            rtpSessionToCallIdMap.put(rtpSessionId, callId);
            log.debug("Added RTP session {} -> Call-ID {} mapping", rtpSessionId, callId);

            // 2. 获取该Call-ID对应的MRCP回调
            MrcpMessageSender.MrcpMessageCallback callback = callIdToMrcpCallbackMap.get(callId);

            if (callback != null) {
                // 3. 为RTP会话注册回调，使用现有的MRCP回调
                mrcpMessageSender.registerCallback(rtpSessionId, callback);
                log.info("Registered MRCP callback for RTP session: {} -> Call-ID: {}", rtpSessionId, callId);
            } else {
                // 这是正常情况：MRCP连接还没有建立，callback会在客户端发送MRCP请求时注册
                log.info("MRCP callback not yet available for Call-ID: {} (normal - waiting for MRCP connection)", callId);
                log.debug("RTP session {} will get callback when MRCP connection is established", rtpSessionId);
                log.debug("Available MRCP callbacks: {}", callIdToMrcpCallbackMap.keySet());
            }

        } catch (Exception e) {
            log.error("Failed to register MRCP callback for RTP session: {}", rtpSessionId, e);
        }
    }

    /**
     * 注册MRCP通道回调
     * 当MRCP连接建立时调用，将回调关联到Call-ID
     */
    public void registerMrcpChannelCallback(String callId, MrcpMessageSender.MrcpMessageCallback callback) {
        try {
            callIdToMrcpCallbackMap.put(callId, callback);
            log.info("Registered MRCP channel callback for Call-ID: {}", callId);
            log.debug("Current callback map size: {}, RTP session map size: {}",
                    callIdToMrcpCallbackMap.size(), rtpSessionToCallIdMap.size());

            // 同时将回调注册到消息发送器的Call-ID键，便于使用callId直接发送
            try {
                mrcpMessageSender.registerCallback(callId, callback);
                log.debug("Registered MRCP sender callback under Call-ID key: {}", callId);
            } catch (Exception e) {
                log.warn("Failed to register MRCP sender callback for Call-ID key {}: {}", callId, e.getMessage());
            }

            // 检查是否有已经存在的RTP会话需要关联这个回调
            rtpSessionToCallIdMap.entrySet().stream()
                    .filter(entry -> callId.equals(entry.getValue()))
                    .forEach(entry -> {
                        String rtpSessionId = entry.getKey();
                        mrcpMessageSender.registerCallback(rtpSessionId, callback);
                        log.info("Associated existing RTP session {} with MRCP callback for Call-ID: {}",
                                rtpSessionId, callId);
                    });

        } catch (Exception e) {
            log.error("Failed to register MRCP channel callback for Call-ID: {}", callId, e);
        }
    }

    /**
     * 注销MRCP回调
     */
    public void unregisterMrcpCallbacks(String callId) {
        try {
            // 1. 注销Call-ID的回调
            callIdToMrcpCallbackMap.remove(callId);
            try {
                mrcpMessageSender.unregisterCallback(callId);
                log.debug("Unregistered MRCP sender callback for Call-ID key: {}", callId);
            } catch (Exception ignored) {}

            // 2. 注销所有相关的RTP会话回调
            rtpSessionToCallIdMap.entrySet().stream()
                    .filter(entry -> callId.equals(entry.getValue()))
                    .forEach(entry -> {
                        String rtpSessionId = entry.getKey();
                        mrcpMessageSender.unregisterCallback(rtpSessionId);
                        rtpSessionToCallIdMap.remove(rtpSessionId);
                        log.debug("Unregistered MRCP callback for RTP session: {}", rtpSessionId);
                    });

            log.info("Unregistered all MRCP callbacks for Call-ID: {}", callId);

        } catch (Exception e) {
            log.error("Failed to unregister MRCP callbacks for Call-ID: {}", callId, e);
        }
    }
    
    /**
     * 根据RTP会话ID获取对应的Call-ID
     * 用于在processAudioData中正确映射会话
     */
    public String getCallIdByRtpSessionId(String rtpSessionId) {
        return rtpSessionToCallIdMap.get(rtpSessionId);
    }
}
